/*
 * Copyright (C) 2011 JiangHongTiao <jjurco.sk_gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package sk.lieskove.jianghongtiao.websearch.persistence;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import sk.lieskove.jianghongtiao.common.utils.PropertiesUtils;
import sk.lieskove.jianghongtiao.multithreaddownloader.document.RemoteDocument;
import sk.lieskove.jianghongtiao.websearch.document.preprocessing.SupportedLanguages;

import javax.persistence.*;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.UUID;
import sk.lieskove.jianghongtiao.websearch.service.ExcludeReasonEnum;

/**
 * Date of create: Jul 12, 2011
 *
 * @author JiangHongTiao <jjurco.sk_gmail.com>
 * @version 2011.0712
 */
@Entity
public class WebSearchResponse implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    /**
     * name of the search engine where the resource was found
     */
    private String serviceName;
    /**
     * unique identifier of the download
     */
    private String uuid;
    /**
     * URL of the found resource
     */
    @Lob
    private String url;
    /**
     * order of result given by search engine
     */
    private Integer searchPosition;
    /**
     * title of the document
     */
    private String title;
    /**
     * short description of the found resource
     */
    @Lob
    private String description;
    /**
     * address of the proxy server used
     */
    private String proxyString;
    /**
     * character set of the document
     */
    private String encoding;
    /**
     * detected language of the text in the file
     */
    @Enumerated(EnumType.STRING)
    private SupportedLanguages languageName;
    /**
     * mime type of the original document
     */
    private String mimeType;
    /**
     * response code returned by server
     */
    private Integer responseStatusCode;
    /**
     * original file downloaded from the server
     */
    @Transient
    private File originalFile;
    /**
     * modified file after applying filters and preprocessing actions
     */
    @Transient
    private File file;
    /**
     * location of the modified file
     */
    private String fileLocation;
    /**
     * location of the original file
     */
    private String originalFileLocation;
    /**
     * size of the original file
     */
    private Long fileSize;
    /**
     * time when the source was downloaded
     */
    private Timestamp fetchTime;
    /*
     * used search query
     */
    private String searchQuery;
    /**
     * how long took fetch document
     */
    private Timestamp loadingTime;
    @Transient
    private transient Logger log = Logger.getLogger(WebSearchResponse.class);
    /**
     * if document can be used for processing
     */
    @Enumerated(EnumType.STRING)
    private ExcludeReasonEnum excludeReason;
    @Transient
    private transient PropertiesUtils pu = new PropertiesUtils(WebSearchResponse.class);
    private transient final boolean delImmediately =
            Boolean.parseBoolean(pu.getProperty("delete-unused-files-immediately"));
    @OneToOne(mappedBy = "webSearchResponse")
    private ClassificationStorage classificationStorage;

    public WebSearchResponse(UUID uuid, String url, String title,
            String description, String serviceName, int searchPosition) {
        this.uuid = uuid.toString();
        this.url = url.replace('\u0000', ' ');
        this.title = title.replace('\u0000', ' ');
        this.description = description.replace('\u0000', ' ');
        this.serviceName = serviceName.replace('\u0000', ' ');
        this.searchPosition = searchPosition;
    }

    /**
     * set following properties:
     * <ul>
     *   <li>proxyString</li>
     *   <li>charset</li>
     *   <li>mimeType</li>
     *   <li>responseStatusCode</li>
     *   <li>originalFile</li>
     *   <li>file</li>
     *   <li>fileSize</li>
     *   <li>fetchTime</li>
     *   <li>loadingTime</li>
     *   <li>url</li>
     * </ul>
     * DO NOT SET:
     * <ul>
     *   <li>serviceName</li>
     *   <li>uuid</li>
     *   <li>searchPosition</li>
     *   <li>title</li>
     *   <li>description</li>
     * </ul>
     * @param doc 
     */
    public void setRemoteDocument(RemoteDocument doc) {
        if (doc == null) {
            throw new NullPointerException("RemoteDocument is null");
        }
        this.proxyString = doc.getProxyString();
        if (doc.getEncoding() != null) {
            this.encoding = doc.getEncoding().displayName().replace('\u0000', ' ');
        }
        this.mimeType = doc.getMimeType();
        if (doc.getReturnCode() != null) {
            this.responseStatusCode = doc.getReturnCode().getCode();
        }
        File f = null;
        if (doc.getFile() != null) {
            try {
                String tmpDir = pu.getProperty("temporary-directory", null);
                if (tmpDir != null) {
                    f = File.createTempFile("ws-backup", "", new File(tmpDir));
                } else {
                    f = File.createTempFile("ws-backup", "");
                }
                String del = pu.getProperty("delete-on-exit", null);
                if (del != null) {
                    if (Boolean.parseBoolean(del)) {
                        f.deleteOnExit();
                    }
                }
                FileUtils.copyFile(doc.getFile(), f);
                setOriginalFile(doc.getFile());
            } catch (IOException ex) {
                log.error("Cannot create backup file: " + f.getAbsolutePath()
                        + " from the file: " + doc.getFile().getAbsolutePath());
            }
            this.fileSize = doc.getFile().length();
            setFile(f);
        }
        this.fetchTime = doc.getFetchTime();
        this.loadingTime = doc.getLoadingTime();
        if (doc.getURL() != null) {
            this.url = doc.getURL().toString().replace('\u0000', ' ');
        }
    }
    private String levenshteinString;
    private int levenshteinDistance;

    public int getLevenshteinDistance() {
        return levenshteinDistance;
    }

    public void setLevenshteinDistance(int levenshteinDistance) {
        this.levenshteinDistance = levenshteinDistance;
    }

    public String getLevenshteinString() {
        return levenshteinString;
    }

    public void setLevenshteinString(String levenshteinString) {
        this.levenshteinString = levenshteinString.replace('\u0000', ' ');
    }
    

    public boolean isAdequateDocument() {
        return excludeReason == null;
    }

    public ExcludeReasonEnum getExcludeReasonEnum() {
        return excludeReason;
    }

    public void setExcludeReasonEnum(ExcludeReasonEnum excludeReasonEnum) {
        this.excludeReason = excludeReasonEnum;
    }

    public SupportedLanguages getLanguageName() {
        return languageName;
    }

    public void setLanguageName(SupportedLanguages language) {
        this.languageName = language;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public WebSearchResponse() {
    }

    public String getServiceName() {
        return serviceName;
    }

    public void setServiceName(String serviceName) {
        this.serviceName = serviceName.replace('\u0000', ' ');
    }

    public Timestamp getFetchTime() {
        return fetchTime;
    }

    public void setFetchTime(Timestamp fetchTime) {
        this.fetchTime = fetchTime;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description.replace('\u0000', ' ');
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title.replace('\u0000', ' ');
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url.replace('\u0000', ' ');
    }

    public String getEncoding() {
        return encoding;
    }

    public void setEncoding(String encoding) {
        this.encoding = encoding.replace('\u0000', ' ');
    }

    public File getFile() {
        return file;
    }

    /**
     * Set new file. Old file is deleted if settings option delete-unused-files-immediately
     * is set to true.
     * @param file replace old file with this new one
     */
    public void setFile(File file) {
        if ((delImmediately) && (this.file != null) && (this.file.exists())) {
            this.file.delete();
        }
        this.file = file;
        fileLocation = file.getAbsolutePath();
    }

    public Timestamp getLoadingTime() {
        return loadingTime;
    }

    public void setLoadingTime(Timestamp loadingTime) {
        this.loadingTime = loadingTime;
    }

    public String getMimeType() {
        return mimeType;
    }

    public void setMimeType(String mimeType) {
        this.mimeType = mimeType.replace('\u0000', ' ');
    }

    public File getOriginalFile() {
        return originalFile;
    }

    /**
     * Set new file. Old file is deleted if settings option delete-unused-files-immediately
     * is set to true.
     * 
     * @param originalFile replace old file with this new one
     */
    public void setOriginalFile(File originalFile) {
        if ((delImmediately) && (this.originalFile != null) && 
                (this.originalFile.exists())) {
            this.originalFile.delete();
        }
        this.originalFile = originalFile;
        this.originalFileLocation = originalFile.getAbsolutePath();
    }

    public String getProxyString() {
        return proxyString;
    }

    public void setProxyString(String proxyString) {
        this.proxyString = proxyString.replace('\u0000', ' ');
    }

    public Integer getResponseStatusCode() {
        return responseStatusCode;
    }

    public void setResponseStatusCode(Integer responseStatusCode) {
        this.responseStatusCode = responseStatusCode;
    }

    public Integer getSearchPosition() {
        return searchPosition;
    }

    public void setSearchPosition(Integer searchPosition) {
        this.searchPosition = searchPosition;
    }

    public String getUuid() {
        return uuid.toString();
    }

    public void setUuid(String uuid) {
        this.uuid = uuid.replace('\u0000', ' ');
    }

    public UUID getUuidObj() {
        return UUID.fromString(uuid);
    }

    public void setUuidObj(UUID uuid) {
        this.uuid = uuid.toString();
    }

    public Long getFileSize() {
        return fileSize;
    }

    public void setFileSize(Long fileSize) {
        this.fileSize = fileSize;
    }

    @Override
    public String toString() {
        return "WebSearchResponse{" + "serviceName=" + serviceName
                + ", url=" + url + ", encoding=" + encoding
                + ", mimeType=" + mimeType + ", originalFile=" + originalFile
                + ", file=" + file + ", excludeReason=" + excludeReason
                + ", lang=" + languageName + '}';
    }

    public String getSearchQuery() {
        return searchQuery;
    }

    public void setSearchQuery(String searchQuery) {
        this.searchQuery = searchQuery.replace('\u0000', ' ');
    }

    public String getFileLocation() {
        return fileLocation;
    }

    public void setFileLocation(String fileLocation) {
        this.fileLocation = fileLocation.replace('\u0000', ' ');
        file = new File(fileLocation.replace('\u0000', ' '));
    }

    public String getOriginalFileLocation() {
        return originalFileLocation;
    }

    public void setOriginalFileLocation(String originalFileLocation) {
        this.originalFileLocation = originalFileLocation.replace('\u0000', ' ');
        originalFile = new File(originalFileLocation.replace('\u0000', ' '));
    }
}
